// (C) Copyright 2012 Enlightv. All rights reserved.

`timescale 1ns/100ps

module dsp48_blending_core
#(parameter
    DATA_BW = 8,
    ALPHA_BW = 8,
    MULT_PRECISION = 6
)
(
    input  I_sclk,
    input  I_clr,
    //
    input  [ DATA_BW - 1: 0] I_a,
    input  [ DATA_BW - 1: 0] I_b,
    input  [ ALPHA_BW - 1: 0] I_alpha,
    input  I_valid,
    //
    output [ DATA_BW - 1: 0] O_result, // result = (A - B) * alpha + B, 4 level delay
    output O_valid
);

/******************************************************************************
                                <localparams>
******************************************************************************/

/******************************************************************************
                              <internal signals>
******************************************************************************/
reg  signed [ (1 + DATA_BW) - 1: 0] c0_A;
reg  signed [ (1 + DATA_BW) - 1: 0] c0_B;
reg  [ ALPHA_BW - 1: 0] c0_alpha;
reg  c0_valid;

reg  signed [ (1 + DATA_BW + 1) - 1: 0] c1_A_minus_B;
reg  [ (1 + DATA_BW) - 1: 0] c1_B;
reg  [ ALPHA_BW - 1: 0] c1_alpha;
reg  c1_valid;

reg  signed [ (1 + DATA_BW + 1) + (1 + MULT_PRECISION) - 1: 0] c2_C;
reg  [ (1 + DATA_BW) - 1: 0] c2_B;
reg  c2_valid;

reg  signed [ (1 + DATA_BW + 1) + (1 + MULT_PRECISION) + 1 - 1: 0] c3_D;
reg  c3_valid;

/******************************************************************************
                                <module body>
******************************************************************************/
// cycle0
always @(posedge I_sclk)
    begin
    c0_A <= $signed({1'b0,I_a});
    c0_B <= $signed({1'b0,I_b});
    c0_alpha <= I_alpha;
    c0_valid <= I_clr ? 1'b0 : I_valid;
    end

// cycle1
always @(posedge I_sclk)
    begin
    c1_A_minus_B <= c0_A - c0_B;
    c1_B <= c0_B;
    c1_alpha <= c0_alpha;
    c1_valid <= I_clr ? 1'b0 : c0_valid;
    end

// cycle2
always @(posedge I_sclk)
    begin
    c2_C <= $signed(c1_A_minus_B) * $signed({1'b0,c1_alpha[ALPHA_BW-1:ALPHA_BW-1-(MULT_PRECISION-1)]});
    c2_B <= c1_B;
    c2_valid <= I_clr ? 1'b0 : c1_valid;
    end

// cycle3
always @(posedge I_sclk)
    begin
    c3_D <= $signed(c2_C) + $signed({1'b0,c2_B,{MULT_PRECISION{1'b0}}});
    c3_valid <= I_clr ? 1'b0 : c2_valid;
    end

assign O_result = c3_D[MULT_PRECISION+DATA_BW-1:MULT_PRECISION];
assign O_valid = c3_valid;

endmodule

